/**
 * @(#)WebUtils.java 2011-9-13
 * 
 * Copyright 2000-2011 by ChinanetCenter Corporation.
 *
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * ChinanetCenter Corporation ("Confidential Information").  You
 * shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement
 * you entered into with ChinanetCenter.
 * 
 */

package com.szf.base.web;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.zip.GZIPOutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.util.WebUtils;

import com.szf.util.JsonUtil;
import com.szf.util.StringUtil;

public abstract class WebUtil {

	private static final Logger logger = LoggerFactory.getLogger(WebUtil.class);

	// -- header 常量定义 --//
	private static final String ENCODING_PREFIX = "encoding";
	private static final String NOCACHE_PREFIX = "no-cache";
	private static final String ENCODING_DEFAULT = "UTF-8";
	private static final boolean NOCACHE_DEFAULT = true;

	// -- content-type 常量定义 --//
	private static final String TEXT_TYPE = "text/plain";
	private static final String JSON_TYPE = "application/json";
	private static final String XML_TYPE = "text/xml";
	private static final String HTML_TYPE = "text/html";

	/**
	 * 设置让浏览器弹出下载对话框的Header.
	 * 
	 * @param fileName 下载后的文件名.
	 */
	public static void setDownloadableHeader(HttpServletResponse response, String fileName) {
		response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
	}

	/**
	 * 设置LastModified Header.
	 */
	public static void setLastModifiedHeader(HttpServletResponse response, long lastModifiedDate) {
		response.setDateHeader("Last-Modified", lastModifiedDate);
	}

	/**
	 * 设置Etag Header.
	 */
	public static void setEtag(HttpServletResponse response, String etag) {
		response.setHeader("ETag", etag);
	}

	/**
	 * 设置过期时间 Header.
	 */
	public static void setExpiresHeader(HttpServletResponse response, long expiresSeconds) {
		//Http 1.0 header
		response.setDateHeader("Expires", System.currentTimeMillis() + expiresSeconds * 1000);
		//Http 1.1 header
		response.setHeader("Cache-Control", "max-age=" + expiresSeconds);
	}

	/**
	 * 设置无缓存Header.
	 */
	public static void setNoCacheHeader(HttpServletResponse response) {
		//Http 1.0 header
		response.setDateHeader("Expires", 0);
		//Http 1.1 header
		response.setHeader("Cache-Control", "max-age=0");
	}

	/**
	 * 检查浏览器客户端是否支持gzip编码.
	 */
	public static boolean checkAccetptGzip(HttpServletRequest request) {
		//Http1.1 header
		String acceptEncoding = request.getHeader("Accept-Encoding");

		if (StringUtil.contains(acceptEncoding, "gzip")) {
			return true;
		}
		else {
			return false;
		}
	}

	/**
	 * 设置Gzip Header并返回GZIPOutputStream.
	 */
	public static OutputStream buildGzipOutputStream(HttpServletResponse response)
			throws IOException {
		response.setHeader("Content-Encoding", "gzip");
		return new GZIPOutputStream(response.getOutputStream());
	}

	/**
	 * 根据浏览器If-Modified-Since Header, 计算文件是否已修改.
	 * 如果无修改, checkIfModify返回false ,设置304 not modify status.
	 */
	public static boolean checkIfModifiedSince(HttpServletRequest request,
			HttpServletResponse response, long lastModified) {
		long ifModifiedSince = request.getDateHeader("If-Modified-Since");
		if ((ifModifiedSince != -1) && (lastModified < ifModifiedSince + 1000)) {
			response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
			return false;
		}
		return true;
	}

	/**
	 * 根据浏览器 If-None-Match Header,计算Etag是否无效.
	 * 
	 * 如果Etag有效,checkIfNoneMatch返回false, 设置304 not modify status.
	 */
	public static boolean checkIfNoneMatchEtag(HttpServletRequest request,
			HttpServletResponse response, String etag) {
		String headerValue = request.getHeader("If-None-Match");
		if (headerValue != null) {
			boolean conditionSatisfied = false;
			if (!headerValue.equals("*")) {
				StringTokenizer commaTokenizer = new StringTokenizer(headerValue, ",");

				while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
					String currentToken = commaTokenizer.nextToken();
					if (currentToken.trim().equals(etag)) {
						conditionSatisfied = true;
					}
				}
			}
			else {
				conditionSatisfied = true;
			}

			if (conditionSatisfied) {
				response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
				response.setHeader("ETag", etag);
				return false;
			}
		}
		return true;
	}

	/**
	 * 取得带相同前缀的Request Parameters.
	 * 
	 * 返回的结果Parameter名已去除前缀. Map的value类型实际上总是<code>String<code>(单值)或<code>String[]</code>(多值)
	 */
	public static Map<String, Object> getParametersStartingWith(HttpServletRequest request,
			String prefix) {
		return WebUtils.getParametersStartingWith(request, prefix);
	}

	/**
	 * 获取客户端IP，包含考虑使用WSA加速的情况。
	 * 
	 * @param request
	 * @return
	 */
	public static String getClientIP(HttpServletRequest request) {
		String ip = request.getHeader("Cdn-Src-Ip");// 网宿WSA加速需要的客户的真实IP地址
		if (StringUtil.isBlank(ip)) {
			ip = request.getHeader("X-Forwarded-For");
			if (StringUtil.isBlank(ip)) {
				ip = request.getRemoteAddr();
			}
		}
		// win7 localhost 解析为ipv6，判断时带来各种不便，强制改为ipv4
		if ("0:0:0:0:0:0:0:1".equals(ip)) {
			ip = "127.0.0.1";
		}
		return ip;
	}

	public static void setResponseError(HttpServletResponse response, int sc, String msg) {
		try {
			response.sendError(sc, msg);
		}
		catch (IllegalStateException ise) {
		}
		catch (IOException e) {
		}
	}

	// -- 绕过jsp/freemaker直接输出文本的函数 --//

	/**
	 * 直接输出内容的简便函数.
	 * 
	 * eg. <br>
	 * render("text/plain", "hello", "encoding:GBK");<br>
	 * render("text/plain", "hello", "no-cache:false");<br>
	 * render("text/plain", "hello", "encoding:GBK", "no-cache:false");
	 * 
	 * @param headers
	 *            可变的header数组，目前接受的值为"encoding:"或"no-cache:",默认值分别为UTF-8和true.
	 */
	public static void render(HttpServletResponse response, final String contentType,
			final String content, final String... headers) {
		try {
			// 分析headers参数
			String encoding = ENCODING_DEFAULT;
			boolean noCache = NOCACHE_DEFAULT;
			for (String header : headers) {
				String headerName = StringUtil.substringBefore(header, ":");
				String headerValue = StringUtil.substringAfter(header, ":");

				if (StringUtil.equalsIgnoreCase(headerName, ENCODING_PREFIX)) {
					encoding = headerValue;
				}
				else if (StringUtil.equalsIgnoreCase(headerName, NOCACHE_PREFIX)) {
					noCache = Boolean.parseBoolean(headerValue);
				}
				else
					throw new IllegalArgumentException(headerName + "不是一个合法的header类型");
			}

			// 设置headers参数
			String fullContentType = contentType + ";charset=" + encoding;
			response.setContentType(fullContentType);
			if (noCache) {
				response.setHeader("Pragma", "No-cache");
				response.setHeader("Cache-Control", "no-cache");
				response.setDateHeader("Expires", 0);
			}

			response.getWriter().write(content);
			response.getWriter().flush();

		}
		catch (IOException e) {
			logger.error(e.getMessage(), e);
		}
	}

	/**
	 * 直接输出文本.
	 * 
	 * @see #render(HttpServletResponse, String, String, String...)
	 */
	public static void renderText(HttpServletResponse response, final String text,
			final String... headers) {
		render(response, TEXT_TYPE, text, headers);
	}

	/**
	 * 直接输出HTML.
	 * 
	 * @see #render(HttpServletResponse, String, String, String...)
	 */
	public static void renderHtml(HttpServletResponse response, final String html,
			final String... headers) {
		render(response, HTML_TYPE, html, headers);
	}

	/**
	 * 直接输出XML.
	 * 
	 * @see #render(HttpServletResponse, String, String, String...)
	 */
	public static void renderXml(HttpServletResponse response, final String xml,
			final String... headers) {
		render(response, XML_TYPE, xml, headers);
	}

	/**
	 * 直接输出JSON.
	 * 
	 * @param content
	 *            需要输出的对象.
	 * @see #render(HttpServletResponse, String, String, String...)
	 */
	public static void renderJson(HttpServletResponse response, final Object content,
			final String... headers) {
		String jsonString = JsonUtil.toJson(content);
		render(response, JSON_TYPE, jsonString, headers);
	}

	/**
	 * 直接输出blob字段（用于图片显示）
	 * 
	 * @param blob byte[]类型
	 */
	public static void renderBlob(HttpServletResponse response, final byte[] blob) {
		try {
			FileCopyUtils.copy(blob, response.getOutputStream());
		}
		catch (IOException e) {
			logger.error(e.getMessage(), e);
		}
	}

}
